package v1

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strconv"
	"usplatformserver/global"
	"usplatformserver/internal/model"
	"usplatformserver/internal/service"
	"usplatformserver/pkg/app"
	"usplatformserver/pkg/errcode"
	"usplatformserver/pkg/utils"

	"github.com/gin-gonic/gin"
)

type Upload struct{}

func NewUpload() Upload {
	return Upload{}
}

// @Summer 批量上传文件
// @Produce json
// @Param files formData file true "files"
// @Success 200 {object} model.SwaggerSuccess "成功"
// @Failure 400 {object} errcode.Error "请求错误"
// @Failure 500 {object} errcode.Error "内部错误"
// @Router /api/v1/upload/files [post]
func (u Upload) HandleUploadMultipleFile(c *gin.Context) {

	response := app.NewResponse(c)
	form, err := c.MultipartForm()
	if err != nil {
		global.Logger.Infof("multipartForm err: %v", err)
		response.ToErrorResponse(errcode.ErrorUploadFileFail)
		return
	}
	files := form.File["files"]

	exePath, _ := os.Executable()
	exeDir := filepath.Dir(exePath)
	uploadPath := fmt.Sprintf("%s/uploadFiles", exeDir)
	fmt.Println("uploadPath: ", uploadPath)
	if isExists, _ := utils.PathExists(uploadPath); !isExists {
		err := os.Mkdir(uploadPath, 0777)
		if nil != err {
			global.Logger.Infof("创建%s文件夹失败", uploadPath)
			response.ToErrorResponse(errcode.ServerError)
			return
		}
	}

	for _, file := range files {
		dstFileName := fmt.Sprintf("%s/%s", uploadPath, file.Filename)
		err := c.SaveUploadedFile(file, dstFileName)
		if err != nil {
			response.ToErrorResponse(errcode.ErrorCreateFileFail)
			return
		}
	}

	//回复上传
	response.ToResponseSuccess()
}

// @Summer 单文件上传
// @Produce json
// @Param file formData file true "file"
// @Success 200 {object} model.UploadFileSuccess "成功"
// @Failure 400 {object} errcode.Error "请求错误"
// @Failure 500 {object} errcode.Error "内部错误"
// @Router /api/v1/upload/file [post]
func (u Upload) HandleUploadFile(c *gin.Context) {
	response := app.NewResponse(c)
	svc := service.New(c.Request.Context())

	file, header, err := c.Request.FormFile("file")
	if err != nil {
		fmt.Println(err)
		response.ToErrorResponse(errcode.ErrorUploadFileFail)
		return
	}

	//获取文件名
	fileName := header.Filename
	fmt.Println("upload file name: ", fileName)
	if isExist, err := svc.IsExistUploadFile(fileName); isExist || err != nil {
		response.ToErrorResponse(errcode.ErrorUploadFileExist)
		return
	}
	var organType int = 0
	tmp := c.Request.FormValue("organType")
	fmt.Println("organType: ", tmp)
	if tmp != "" {
		organType, _ = strconv.Atoi(tmp)
	}
	uploadPath := fmt.Sprintf("%v/%v", global.AppSettings.UsclientPath, "analysisvideo")
	if isExist, _ := utils.PathExists(uploadPath); !isExist {
		err := os.Mkdir(uploadPath, 0777)
		if nil != err {
			global.Logger.Infof("创建%s文件夹失败", uploadPath)
			response.ToErrorResponse(errcode.ServerError)
			return
		}
	}
	fileFullName := fmt.Sprintf("%s/%v", uploadPath, fileName)
	out, err := os.Create(fileFullName)
	if err != nil {
		global.Logger.Infof("创建%s文件失败", fileFullName)
		response.ToErrorResponse(errcode.ServerError)
		return
	}
	defer out.Close()
	//将读取的文件流写入本地
	_, err = io.Copy(out, file)
	if err != nil {
		global.Logger.Info("读取文件失败")
		response.ToErrorResponse(errcode.ErrorReadFileFail)
		return
	}

	//文件名唯一性二次判断
	if isExist, err := svc.IsExistUploadFile(fileName); isExist || err != nil {
		response.ToErrorResponse(errcode.ErrorUploadFileExist)
		return
	}

	//视频文件信息存入数据库
	fileSize := fmt.Sprintf("%.2f KB", float64(header.Size)/1024.0)
	fmt.Println("file size: ", fileSize)

	id, err := svc.InsertUploadFile(organType, fileName, fileFullName, fileSize)
	if err != nil {
		global.Logger.Infof("insert upload file failed: %v", err)
	}
	//发布视频分析任务
	addr := fmt.Sprintf("tcp://%v:%d", global.ZMQSettings.Addr, global.ZMQSettings.Port)
	go svc.PubAnalysisTask(addr, id, fileName, fileFullName)

	//上传完成
	response.ToResponse(gin.H{
		"id": id,
	})
}

// @Summer 离线图片zip文件上传
// @Produce json
// @Param file formData file true "file"
// @Success 200 {object} model.UploadFileSuccess "成功"
// @Failure 400 {object} errcode.Error "请求错误"
// @Failure 500 {object} errcode.Error "内部错误"
// @Router /api/v1/upload/offline/images [post]
func (u Upload) HandleUploadOfflineImages(c *gin.Context) {
	response := app.NewResponse(c)
	svc := service.New(c.Request.Context())

	file, header, err := c.Request.FormFile("file")
	tmp := c.Request.FormValue("organType")
	fmt.Println("organType: ", tmp)
	var organType int = 0
	fileName := c.Request.FormValue("fileName")
	if tmp != "" {
		organType, _ = strconv.Atoi(tmp)
	}

	if err != nil {
		fmt.Println(err)
		response.ToErrorResponse(errcode.ErrorUploadFileFail)
		return
	}

	if fileName == "" {
		response.ToErrorResponse(errcode.ErrorUploadFileFail)
		return
	}

	//文件大小与可用空间比较，差值小于2GB报磁盘空间不足
	filePath := "/"
	disk, err2 := svc.DiskUsage(filePath)
	if err2 == nil && disk.Free-uint64(header.Size) < 2*1024*1024 {
		response.ToErrorResponse(errcode.ErrorNotEnoughDiskSpace)
		return
	}

	//获取文件名
	fmt.Println("upload file name: ", fileName)
	fileFullName := fmt.Sprintf("%s/%v", global.AppSettings.UsclientPath, fileName)
	out, err := os.Create(fileFullName)
	if err != nil {
		global.Logger.Infof("创建%s文件失败", fileFullName)
		response.ToErrorResponse(errcode.ServerError)
		return
	}
	defer out.Close()
	//将读取的文件流写入本地
	_, err = io.Copy(out, file)
	if err != nil {
		global.Logger.Info("读取文件失败")
		response.ToErrorResponse(errcode.ErrorReadFileFail)
		return
	}

	//离线文件信息存入数据库
	fileSize := fmt.Sprintf("%.2f KB", float64(header.Size)/1024.0)
	fmt.Println("file size: ", fileSize)

	id, err := svc.InsertUploadFile(organType, fileName, fileFullName, fileSize)
	if err != nil {
		global.Logger.Infof("insert upload file failed: %v", err)
	}
	//发布视频分析任务
	addr := fmt.Sprintf("tcp://%v:%d", global.ZMQSettings.Addr, global.ZMQSettings.Port)
	err = svc.PubAnalysisOfflineImagesTask(addr, organType, id, fileName, fileFullName)

	if err != nil {
		global.Logger.Info("发布分析任务失败")
		svc.DeleteUploadFile(id) //删除入库数据
		response.ToErrorResponse(errcode.ErrorUploadFileFail)
		return
	}

	//上传完成
	response.ToResponse(gin.H{
		"id": id,
	})
}

// @Summer 获取上传文件列表
// @Produce json
// @Param organType query int true "检查列席"
// @Param option query string false "搜索条件" maxlength(100)
// @Param beginTime query string false "起始时间"
// @param endTime query string false "截止时间"
// @Param page query int false "页码"
// @Param pageSize query int false "每页数量"
// @Success 200 {object} model.UploadFileListSwagger "成功"
// @Failure 400 {object} errcode.Error "请求错误"
// @Failure 500 {object} errcode.Error "内部错误"
// @Router /api/v1/upload/files [get]
func (u Upload) List(c *gin.Context) {
	param := service.UploadListRequest{}
	response := app.NewResponse(c)

	fmt.Println("pageSize: ", response.Ctx.Query("pageSize"))

	valid, errs := app.BindAndValid(c, &param)
	if !valid {
		response.ToErrorResponse(errcode.InvalidParams.WithDetails(errs.Errors()...))
		return
	}

	svc := service.New(c.Request.Context())
	pager := app.Pager{
		Page:     app.GetPage(c),
		PageSize: app.GetPageSize(c),
	}

	totalRows, err := svc.CountUploadFile(&param)
	if err != nil {
		response.ToErrorResponse(errcode.ErrorGetUploadFileCountFail)
		return
	}

	uploadFiles, err := svc.GetUploadFileList(&param, &pager)
	if err != nil {
		response.ToErrorResponse(errcode.ErrorGetUploadFileListFail)
		return
	}
	response.ToResponseList(uploadFiles, totalRows)
}

// @Summer 上传文件高亮
// @Produce json
// @Param fileId query int true "文件ID"
// @Param option query string false "搜索条件" maxlength(100)
// @Param beginTime query string false "起始时间"
// @param endTime query string false "截止时间"
// @Param pageSize query int true "每页数量"
// @Param organType query int true "检查部位"
// @Success 200 {object} model.UploadFileHighLightSuccess "成功"
// @Failure 400 {object} errcode.Error "请求错误"
// @Failure 500 {object} errcode.Error "内部错误"
// @Router /api/v1/upload/file/highlight [get]
func (u Upload) UploadHighlight(c *gin.Context) {
	param := service.UploadFileHighlightRequest{}
	response := app.NewResponse(c)

	global.Logger.Info("enter upload high light")

	valid, errs := app.BindAndValid(c, &param)
	if !valid {
		response.ToErrorResponse(errcode.InvalidParams.WithDetails(errs.Errors()...))
		return
	}

	svc := service.New(c.Request.Context())
	//页码
	pager := app.Pager{
		Page:     0,
		PageSize: *param.PageSize,
	}
	//获取总条数参数
	totalParam := service.UploadListRequest{
		Option:    param.Option,
		BeginTime: param.BeginTime,
		EndTime:   param.EndTime,
		OrganType: param.OrganType,
	}
	//获取搜索条件下数据总数
	totalRows, err := svc.CountUploadFile(&totalParam)
	fmt.Println("CountUploadFile err: ", err)
	if err != nil {
		response.ToErrorResponse(errcode.ErrorGetUploadFileCountFail)
		return
	}
	fmt.Println("totalRows: ", totalRows)
	//根据fileId与数据总数，粗略计算页码
	pageTotal := totalRows/pager.PageSize + totalRows%pager.PageSize
	//文件所在页
	ret := model.UploadFilePage{
		Page: 0,
	}
	//遍历页码寻找文件
	for i := 1; i <= pageTotal; i++ {
		pager.Page = i
		uploadFiles, err := svc.GetUploadFileList(&totalParam, &pager)
		if err != nil {
			response.ToErrorResponse(errcode.ErrorGetUploadFileListFail)
			return
		}
		for _, u := range uploadFiles {
			if u.ID == *param.FileId {
				ret.Page = i
				break
			}
		}
	}
	//回复文件所在页码
	response.ToResponse(ret)
}
